home *** CD-ROM | disk | FTP | other *** search
- char *ckzv = "GEM file support, 5A(059) 16 Jul 92";
-
- /* C K S F I O -- Kermit file system support for Atari ST systems */
-
- /*
- Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
- Columbia University Center for Computing Activities. Many other contributors.
- First released January 1985.
- Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
- York. Permission is granted to any individual or institution to use this
- software as long as it is not sold for profit. This copyright notice must be
- retained. This software may not be included in commercial products without
- written permission of Columbia University.
- Extensively modified by: Bruce Moore (mooreb@iccgcc.decnet.ab.com).
- */
-
- /* Include Files */
-
- #include "ckcdeb.h"
-
- /* Directory structure header file */
-
- #ifdef SDIRENT
- #define DIRENT
- #endif
-
- #ifdef GEMDOS
- #define TIMESTAMP /* Can do file dates */
- #include <time.h> /* System time stuff */
- extern long timezone;
- extern int dstadjust;
- #endif
-
- /* Is `y' a leap year? */
- #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
-
- /* Number of leap years from 1970 to `y' (not including `y' itself). */
- #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
-
- #include <stat.h> /* File status */
-
- /*
- Functions (n is one of the predefined file numbers from ckcker.h):
-
- zopeni(n,name) -- Opens an existing file for input.
- zopeno(n,name,attr,fcb) -- Opens a new file for output.
- zclose(n) -- Closes a file.
- zchin(n,&c) -- Gets the next character from an input file.
- zsinl(n,&s,x) -- Read a line from file n, max len x, into address s.
- zsout(n,s) -- Write a null-terminated string to output file, buffered.
- zsoutl(n,s) -- Like zsout, but appends a line terminator.
- zsoutx(n,s,x) -- Write x characters to output file, unbuffered.
- zchout(n,c) -- Add a character to an output file, unbuffered.
- zchki(name) -- Check if named file exists and is readable, return size.
- zchko(name) -- Check if named file can be created.
- zchkspa(name,n) -- Check if n bytes available to create new file, name.
- znewn(name,s) -- Make a new unique file name based on the given name.
- zdelet(name) -- Delete the named file.
- zxpand(string) -- Expands the given wildcard string into a list of files.
- znext(string) -- Returns the next file from the list in "string".
- zxcmd(n,cmd) -- Execute the command in a lower fork on file number n.
- zclosf() -- Close input file associated with zxcmd()'s lower fork.
- zrtol(n1,n2) -- Convert remote filename into local form.
- zltor(n1,n2) -- Convert local filename into remote form.
- zchdir(dirnam) -- Change working directory.
- zhome() -- Return pointer to home directory name string.
- zkself() -- Kill self, log out own job.
- zsattr(struct zattr *) -- Return attributes for file which is being sent.
- zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
- zrename(old, new) -- Rename a file.
- */
-
- /* Kermit-specific includes */
- /*
- Definitions here supersede those from system include files.
- ckcdeb.h is included above.
- */
- #include "ckcker.h" /* Kermit definitions */
- #include "ckucmd.h" /* For sys-dependent keyword tables */
- #include "ckuver.h"
-
- char *ckzsys = HERALD;
-
- /* Definitions of some Unix system commands */
-
- char *DELCMD = "rm "; /* For file deletion */
- char *PWDCMD = "pwd "; /* For saying where I am */
- char *DIRCMD = "ls -l "; /* For directory listing */
- char *DIRCM2 = "ls -l "; /* For directory listing, no args */
- char *TYPCMD = "cat "; /* For typing a file */
- char *SPACMD = "df $cwd";
- char *SPACM2 = "df "; /* For space in specified directory */
- char *WHOCMD = "echo just we frogs "; /* For seeing who's logged in */
-
- #ifdef DTILDE /* For tilde expansion */
- _PROTOTYP( char * tilde_expand, (char *) );
- #endif /* DTILDE */
-
- /* More system-dependent includes, which depend on symbols defined */
- /* in the Kermit-specific includes. Oh what a tangled web we weave... */
-
- #include <access.h> /* File access */
- #include <osbind.h> /* GEM o.s. bindings */
-
- #ifndef S_ISREG
- #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
- #endif /* S_ISREG */
- #ifndef S_ISDIR
- #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
- #endif /* S_ISDIR */
-
- /* Define maximum length for a file name if not already defined */
-
- #ifndef MAXNAMLEN
- #define MAXNAMLEN 12
- #endif /* MAXNAMLEN */
-
- /* Longest pathname */
-
- #ifndef MAXPATH
- #define MAXPATH 255
- #endif /* MAXPATH */
-
- /* Maximum number of filenames for wildcard expansion */
-
- #define MAXWLD 50
-
- /* More internal function prototypes */
- /*
- * The path structure is used to represent the name to match.
- * Each slash-separated segment of the name is kept in one
- * such structure, and they are linked together, to make
- * traversing the name easier.
- */
- struct path {
- char npart[MAXNAMLEN+4]; /* name part of path segment */
- struct path *fwd; /* forward ptr */
- };
- _PROTOTYP( int shxpand, (char *, char **, int ) );
- _PROTOTYP( static int fgen, (char *, char **, int ) );
- _PROTOTYP( static VOID traverse, (struct path *, char *, char *) );
- _PROTOTYP( static VOID addresult, (char *) );
- _PROTOTYP( static int match, (char *, char *) );
- _PROTOTYP( char * xindex, (char *, char) );
- _PROTOTYP( UID_T real_uid, (void) );
- _PROTOTYP( struct path *splitpath, (char *p) );
-
- /* Some systems define these symbols in include files, others don't... */
-
- #ifndef R_OK
- #define R_OK AREAD /* For access */
- #endif
-
- #ifndef W_OK
- #define W_OK AWRITE
- #endif
-
- #ifndef O_RDONLY
- #define O_RDONLY 000
- #endif
-
- /* Declarations */
-
- int maxnam = MAXNAMLEN; /* Available to the outside */
- int maxpath = MAXPATH;
-
- FILE *fp[ZNFILS] = { /* File pointers */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL };
-
- /* (PWP) external def. of things used in buffered file input and output */
- #ifdef DYNAMIC
- extern CHAR *zinbuffer, *zoutbuffer;
- #else
- extern CHAR zinbuffer[], zoutbuffer[];
- #endif /* DYNAMIC */
- extern CHAR *zinptr, *zoutptr;
- extern int zincnt, zoutcnt;
- extern int wildxpand;
-
- static long iflen = -1L; /* Input file length */
-
- static int pid = 0; /* pid of child fork */
- static int fcount; /* Number of files in wild group */
- static char nambuf[MAXNAMLEN+4]; /* Buffer for a filename */
- static char pipename[8*MAXNAMLEN]; /* Pipe name */
- static char zmbuf[200]; /* For mail, remote print strings */
- char *malloc(), *getenv(), *strcpy(); /* System functions */
- extern char *strrchr(), *strcat(); /* and a couple more */
- extern char *strchr(), *strncpy(); /* and yet more */
- extern errno; /* System error code */
-
- /* static */ /* Not static, must be global now. */
- char *mtchs[MAXWLD], /* Matches found for filename */
- **mtchptr; /* Pointer to current match */
-
- /* Z K S E L F -- Kill Self: log out own job, if possible. */
-
- /* Note, should get current pid, but if your system doesn't have */
- /* getppid(), then just kill(0,9)... */
-
- zkself() { /* For "bye", but no guarantee! */
- exit(GOOD_EXIT);
- }
-
- /* Z O P E N I -- Open an existing file for input. */
-
- int
- zopeni(n,name) int n; char *name; {
- debug(F111," zopeni",name,n);
- debug(F101," fp","", fp[n]);
- if (chkfn(n) != 0) return(0);
- zincnt = 0; /* Reset input buffer */
- if (n == ZSYSFN) { /* Input from a system function? */
- /*** Note, this function should not be called with ZSYSFN ***/
- /*** Always call zxcmd() directly, and give it the real file number ***/
- /*** you want to use. ***/
- debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
- *nambuf = '\0'; /* No filename. */
- return(0); /* fail. */
- #ifdef COMMENT
- return(zxcmd(n,name)); /* Try to fork the command */
- #endif
- }
- if (n == ZSTDIO) { /* Standard input? */
- if (isatty(0)) {
- fprintf(stderr,"Terminal input not allowed");
- debug(F110,"zopeni: attempts input from unredirected stdin","",0);
- return(0);
- }
- fp[ZIFILE] = stdin;
- return(1);
- }
- fp[n] = fopen(name,"rb"); /* Real file, open it. */
- debug(F111," zopeni", name, fp[n]);
- if (fp[n] == NULL) perror("zopeni");
- return((fp[n] != NULL) ? 1 : 0);
- }
-
- /* Z O P E N O -- Open a new file for output. */
-
- int
- zopeno(n,name,zz,fcb)
- /* zopeno */ int n; char *name; struct zattr *zz; struct filinfo *fcb; {
-
- char p[8]; /* (===OS2 change===) */
- /* char *p; */ /* Local-use pointer */
-
-
- /* As of Version 5A, the attribute structure and the file information */
- /* structure are included in the arglist. */
-
- debug(F111,"zopeno",name,n);
- if (fcb) {
- debug(F101,"zopeno fcb disp","",fcb->dsp);
- debug(F101,"zopeno fcb type","",fcb->typ);
- debug(F101,"zopeno fcb char","",fcb->cs);
- } else {
- debug(F100,"zopeno fcb is NULL","",0);
- }
- if (n != ZDFILE)
- debug(F101," fp[]=stdout", "", fp[n]);
- if (chkfn(n) != 0) return(0);
- if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */
- fp[ZOFILE] = stdout;
- if (n != ZDFILE)
- debug(F101," fp[]=stdout", "", (int) fp[n]);
- zoutcnt = 0;
- zoutptr = zoutbuffer;
- return(1);
- }
-
- /* A real file. Open it in desired mode (create or append). */
-
- strcpy(p,"w"); /* Assume write/create mode */
- if (fcb) { /* If called with an FCB... */
- if (fcb->dsp == XYFZ_A) /* Does it say Append? */
- strcpy(p,"a"); /* Yes. */
- }
- if (n == ZOFILE) strcat(p,"b"); /* Binary mode */
- fp[n] = fopen(name,p); /* Open the file */
-
- if (fp[n] == NULL) {
- perror("zopeno can't open");
- } else {
- if (n == ZDFILE) setbuf(fp[n],NULL); /* Debugging file unbuffered */
- }
- zoutcnt = 0; /* (PWP) reset output buffer */
- zoutptr = zoutbuffer;
- if (n != ZDFILE)
- debug(F101, " fp[n]", "", fp[n]);
- return((fp[n] != NULL) ? 1 : 0);
- }
-
- /* Z C L O S E -- Close the given file. */
-
- /* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */
-
- int
- zclose(n) int n; {
- int x, x2;
- if (chkfn(n) < 1) return(0); /* Check range of n */
-
- if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */
- x2 = zoutdump();
- else
- x2 = 0;
-
- x = 0; /* Initialize return code */
- if (fp[ZSYSFN]) { /* If file is really pipe */
- x = zclosf(n); /* do it specially */
- } else {
- if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]);
- fp[n] = NULL;
- }
- iflen = -1L; /* Invalidate file length */
- if (x == EOF) /* if we got a close error */
- return (-1);
- else if (x2 < 0) /* or an error flushing the last buffer */
- return (-1); /* then return an error */
- else
- return (1);
- }
-
- /* Z C H I N -- Get a character from the input file. */
-
- /* Returns -1 if EOF, 0 otherwise with character returned in argument */
-
- int
- zchin(n,c) int n; int *c; {
- int a, x;
-
- /* (PWP) Just in case this gets called when it shouldn't. */
- if (n == ZIFILE) {
- x = zminchar();
- *c = x;
- return(x);
- }
- /* if (chkfn(n) < 1) return(-1); */
- a = getc(fp[n]);
- if (a == EOF) return(-1);
- *c = (CHAR) a & 0377;
- return(0);
- }
-
- /* Z S I N L -- Read a line from a file */
-
- /*
- Writes the line into the address provided by the caller.
- n is the Kermit "channel number".
- Writing terminates when newline is encountered, newline is not copied.
- Writing also terminates upon EOF or if length x is exhausted.
- Returns 0 on success, -1 on EOF or error.
- */
- int
- zsinl(n,s,x) int n, x; char *s; {
- int a, z = 0;
-
- if (chkfn(n) < 1) { /* Make sure file is open */
- return(-1);
- }
- a = -1;
- while (x--) {
- #ifndef NLCHAR
- int old;
- old = a; /* Previous character */
- #endif
- if (zchin(n,&a) < 0) { /* Read a character from the file */
- z = -1;
- break;
- }
- #ifdef NLCHAR
- if (a == (char) NLCHAR) break; /* Single-character line terminator */
- #else
- if (a == '\r') continue; /* CRLF line terminator */
- if (old == '\r') {
- if (a == '\n') break;
- else *s++ = '\r';
- }
- #endif /* NLCHAR */
- *s = a;
- s++;
- }
- *s = '\0';
- return(z);
- }
-
- /*
- * (PWP) (re)fill the buffered input buffer with data. All file input
- * should go through this routine, usually by calling the zminchar()
- * macro (in ckcker.h).
- */
-
- /*
- * Suggestion: if fread() returns 0, call ferror to find out what the
- * problem was. If it was not EOF, then return -2 instead of -1.
- * Upper layers (getpkt function in ckcfns.c) should set cxseen flag
- * if it gets -2 return from zminchar macro.
- */
- int
- zinfill() {
- int x;
-
- errno = 0;
- zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
- #ifdef COMMENT
- debug(F101,"zinfill fp","",fp[ZIFILE]);
- debug(F101,"zinfill zincnt","",zincnt);
- #endif
- if (zincnt == 0) {
- #ifndef UTEK
- #ifdef ferror
- x = ferror(fp[ZIFILE]);
- debug(F101,"zinfill errno","",errno);
- debug(F101,"zinfill ferror","",x);
- if (x) return(-2);
- #endif /* ferror */
- #else
- x = feof(fp[ZIFILE]);
- debug(F101,"zinfill errno","",errno);
- debug(F101,"zinfill feof","",x);
- if (!x && ferror(fp[ZIFILE])) return(-2);
- #endif /* UTEK */
- return(-1);
- }
- zinptr = zinbuffer; /* set pointer to beginning, (== &zinbuffer[0]) */
- zincnt--; /* one less char in buffer */
- return((int)(*zinptr++) & 0377); /* because we return the first */
- }
-
- /* Z S O U T -- Write a string out to the given file, buffered. */
-
- int
- zsout(n,s) int n; char *s; {
- if (chkfn(n) < 1) return(-1); /* Keep this here, prevents memory faults */
- #ifdef COMMENT
- while (*s) { /* (unbuffered for debugging) */
- write(fileno(fp[n]),s,1); ++s;
- }
- #endif
- #ifdef COMMENT
- return(fputs(s,fp[n]) == EOF ? -1 : 0);
- #else
- #ifdef COMMENT
- if (n == ZSFILE)
- return(write(fileno(fp[n]),s,strlen(s)));
- else
- #endif
- return(fputs(s,fp[n]) == EOF ? -1 : 0);
- #endif
- }
-
- /* Z S O U T L -- Write string to file, with line terminator, buffered */
-
- int
- zsoutl(n,s) int n; char *s; {
- /* if (chkfn(n) < 1) return(-1); */
- if (fputs(s,fp[n]) == EOF) return(-1);
- if (fputs("\n",fp[n]) == EOF) return(-1);
- return(0);
- }
-
- /* Z S O U T X -- Write x characters to file, unbuffered. */
-
- int
- zsoutx(n,s,x) int n, x; char *s; {
- #ifdef COMMENT
- if (chkfn(n) < 1) return(-1);
- return(write(fp[n]->_file,s,x));
- #endif
- return(write(fileno(fp[n]),s,x) == x ? x : -1);
- }
-
-
- /* Z C H O U T -- Add a character to the given file. */
-
- /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */
-
- int
- #ifdef CK_ANSIC
- zchout(register int n, char c)
- #else
- zchout(n,c) register int n; char c;
- #endif /* CK_ANSIC */
- /* zchout() */ {
- /* if (chkfn(n) < 1) return(-1); */
- if (n == ZSFILE) { /* Use unbuffered for session log */
- #ifdef COMMENT
- return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1);
- #else
- if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */
- return(ferror(fp[n])?-1:0); /* Check to make sure */
- else /* Otherwise... */
- return(0); /* There was no error. */
- #endif
- } else { /* Buffered for everything else */
- if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */
- return(ferror(fp[n])?-1:0); /* Check to make sure */
- else /* Otherwise... */
- return(0); /* There was no error. */
- }
- }
-
- /* (PWP) buffered character output routine to speed up file IO */
-
- int
- zoutdump() {
- int x;
- zoutptr = zoutbuffer; /* Reset buffer pointer in all cases */
- debug(F101,"zoutdump chars","",zoutcnt);
- if (zoutcnt == 0) { /* Nothing to output */
- return(0);
- } else if (zoutcnt < 0) { /* Unexpected negative argument */
- zoutcnt = 0; /* Reset output buffer count */
- return(-1); /* and fail. */
- }
-
- /* Frank Prindle suggested that replacing this fwrite() by an fflush() */
- /* followed by a write() would improve the efficiency, especially when */
- /* writing to stdout. Subsequent tests showed a 5-fold improvement! */
- /* if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) { */
-
- fflush(fp[ZOFILE]);
- if ((x = write(fileno(fp[ZOFILE]),zoutbuffer,zoutcnt)) == zoutcnt) {
- debug(F101,"zoutdump write ok","",zoutcnt);
- zoutcnt = 0; /* Reset output buffer count */
- return(0); /* write() worked OK */
- } else {
- debug(F101,"zoutdump write error","",errno);
- debug(F101,"zoutdump write returns","",x);
- zoutcnt = 0; /* Reset output buffer count */
- return(-1); /* write() failed */
- }
- }
-
- /* C H K F N -- Internal function to verify file number is ok */
-
- /*
- Returns:
- -1: File number n is out of range
- 0: n is in range, but file is not open
- 1: n in range and file is open
- */
- int
- chkfn(n) int n; {
- switch (n) {
- case ZCTERM:
- case ZSTDIO:
- case ZIFILE:
- case ZOFILE:
- case ZDFILE:
- case ZTFILE:
- case ZPFILE:
- case ZSFILE:
- case ZSYSFN:
- case ZRFILE:
- case ZWFILE: break;
- default:
- debug(F101,"chkfn: file number out of range","",n);
- fprintf(stderr,"?File number out of range - %d\n",n);
- return(-1);
- }
- return( (fp[n] == NULL) ? 0 : 1 );
- }
-
- /* Z C H K I -- Check if input file exists and is readable */
-
- /*
- Returns:
- >= 0 if the file can be read (returns the size).
- -1 if file doesn't exist or can't be accessed,
- -2 if file exists but is not readable (e.g. a directory file).
- -3 if file exists but protected against read access.
- */
- /*
- For Berkeley Unix, a file must be of type "regular" to be readable.
- Directory files, special files, and symbolic links are not readable.
- */
- long
- zchki(name) char *name; {
- struct stat buf;
- int x;
-
- x = stat(name,&buf);
- if (x < 0) {
- debug(F111,"zchki stat fails",name,errno);
- return(-1);
- }
- if (!S_ISREG (buf.st_mode)) { /* Must be regular file */
- debug(F111,"zchki skipping:",name,x);
- return(-2);
- }
- debug(F111,"zchki stat ok:",name,x);
-
- if ((x = access(name,R_OK)) < 0) { /* Is the file accessible? */
- debug(F111," access failed:",name,x); /* No */
- return(-3);
- } else {
- iflen = buf.st_size; /* Yes, remember size */
- strncpy(nambuf,name,MAXNAMLEN); /* and name globally. */
- debug(F111," access ok:",name,(int) iflen);
- return( (iflen > -1L) ? iflen : 0L );
- }
- }
-
- /* Z C H K O -- Check if output file can be created */
-
- /*
- Returns -1 if write permission for the file would be denied, 0 otherwise.
- */
- int zchko(name) char *name; {
- int i, x;
- char *s;
-
- if (!name) return(-1); /* Watch out for null pointer. */
- x = strlen(name); /* Get length of filename */
- debug(F101," length","",x);
- s = malloc(x+3); /* Must copy because we can't */
- if (!s) { /* write into our argument. */
- fprintf(stderr,"Malloc error 46\n");
- return(-1);
- }
- strcpy(s,name);
-
- for (i = x; i > 0; i--) /* Strip filename from right. */
- if (s[i-1] == '\\') break;
- debug(F101," i","",i);
-
- #ifdef COMMENT
- /* X/OPEN XPG3-compliant systems fail if argument ends with "/"... */
- if (i == 0) /* If no path, use current directory */
- strcpy(s,".\\");
- else /* Otherwise, use given one. */
- s[i] = '\0';
- #else
- /* So now we use "path/." if path given, or "." if no path given. */
- s[i++] = '.'; /* Append "." to path. */
- s[i] = '\0';
- #endif /* COMMENT */
-
- x = access(s,W_OK); /* Check access of path. */
- if (x < 0)
- debug(F111,"zchko access failed:",s,errno);
- else
- debug(F111,"zchko access ok:",s,x);
- free(s); /* Free temporary storage */
- return((x < 0) ? -1 : 0); /* and return. */
- }
-
- /* Z D E L E T -- Delete the named file. */
-
- int
- zdelet(name) char *name; {
- return(unlink(name));
- }
-
-
- /* Z R T O L -- Convert remote filename into local form */
-
- /* For UNIX, this means changing uppercase letters to lowercase. */
- /* For GEM, this means 8.3 filenames and other DOS baggage too */
-
- VOID
- zrtol(name,name2) char *name, *name2; {
- zltor(name, name2);
- for ( ; *name != '\0'; name++) {
- *name2++ = isupper(*name) ? tolower(*name) : *name;
- }
- *name2 = '\0';
- debug(F110,"zrtol:",name2,0);
- }
-
-
- /* Z S T R I P -- Strip device & directory name from file specification */
-
- /* Strip pathname from filename "name", return pointer to result in name2 */
-
- static char work[257]; /* buffer for use by zstrip and zltor */
-
- VOID
- zstrip(name,name2) char *name, **name2; {
- char *cp, *pp;
- debug(F110,"zstrip before",name,0);
- pp = work;
- #ifdef DTILDE
- if (*name == '~') name++;
- #endif
- for (cp = name; *cp != '\0'; cp++) {
- if (*cp == '\\')
- pp = work;
- else
- *pp++ = *cp;
- }
- *pp = '\0'; /* Terminate the string */
- *name2 = work;
- debug(F110,"zstrip after",*name2,0);
- }
-
- /* Z L T O R -- Local TO Remote */
-
- zltor(name,name2) char *name, *name2; {
- char *cp, *pp;
- int dc = 0;
-
- debug(F110,"zltor",name,0);
- pp = work;
- for (cp = name; *cp != '\0'; cp++) { /* strip path name */
- if (*cp == '\\') {
- dc = 0;
- pp = work;
- }
- else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
- else if (*cp == '~') *pp++ = 'X'; /* Change tilde to 'X' */
- else if (*cp == '#') *pp++ = 'X'; /* Change number sign to 'X' */
- else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
- else if (dc == 0 && (cp - name) >= 8) *pp++ = '.'; /* base too long */
- else *pp++ = *cp;
- }
- *pp = '\0'; /* Tie it off. */
- cp = name2; /* If nothing before dot, */
- if (*work == '.') *cp++ = 'X'; /* insert 'X' */
- strcpy(cp,work);
- debug(F110," name2",name2,0);
- }
-
-
- /* Z C H D I R -- Change directory */
- /*
- Call with:
- dirnam = pointer to name of directory to change to,
- which may be "" or NULL to indicate user's home directory.
- Returns:
- 0 on failure
- 1 on success
- */
- int
- zchdir(dirnam) char *dirnam; {
- char *hd, *sp, *p;
-
- debug(F110,"zchdir",dirnam,0);
- if (dirnam == NULL || dirnam == "" || *dirnam == '\0') /* If arg is null */
- dirnam = getenv("HOME"); /* use user's home directory. */
- if (dirnam == NULL)
- return(0);
- sp = dirnam;
- debug(F110,"zchdir 2",dirnam,0);
-
- #ifdef DTILDE
- hd = tilde_expand(dirnam); /* Attempt to expand tilde */
- if (*hd == '\0') hd = dirnam; /* in directory name. */
- #else
- hd = dirnam;
- #endif /* DTILDE */
- debug(F110,"zchdir 3",hd,0);
- if (toschdir(hd) == 0) return(1); /* Try to cd */ /* (===OS2===) */
- p = sp; /* Failed, lowercase it. */
- while (*p) {
- if (isupper(*p)) *p = tolower(*p);
- p++;
- }
- debug(F110,"zchdir 4",hd,0);
- #ifdef DTILDE
- hd = tilde_expand(sp); /* Try again to expand tilde */
- if (*hd == '\0') hd = sp;
- #else
- hd = sp; /* Point to result */
- #endif
- debug(F110,"zchdir 5",hd,0);
- return((toschdir(hd) == 0) ? 1 : 0);
- }
-
- /* T O S C H D I R -- Change directory under TOS */
- /*
- * Return 0 if it worked, 1 otherwise
- */
- int
- toschdir(dirnam) char *dirnam; {
- char *path;
- int drive;
-
- if (path = strchr(dirnam, ':')) {
- drive = toupper(*--path) - 'A';
- if (drive < 0 || drive > 25)
- return(1);
- Dsetdrv(drive);
- path += 2;
- } else
- path = dirnam;
- return((int) Dsetpath(path));
- }
-
- /* Z H O M E -- Return pointer to user's home directory */
-
- char *
- zhome() {
- char *home = NULL;
- home = getenv("HOME");
- return(home ? home : "."); /* (===OS2===) */
- }
-
- /* Z G T D I R -- Return pointer to user's current directory */
-
- #ifdef MAXPATHLEN
- #define CWDBL MAXPATHLEN
- #else
- #define CWDBL 100
- #endif
- static char cwdbuf[CWDBL+1];
-
- char *
- zgtdir() {
- int drive;
- char *p;
- int c;
-
- p = cwdbuf;
- drive = Dgetdrv();
- *p++ = (drive + 'a'); /* Drive letter */
- *p++ = ':';
- Dgetpath(p, 0); /* Rest of path */
- for (p = cwdbuf; c = *p; p++) {
- if (isupper(c))
- *p = _tolower(c);
- }
- if (strlen(cwdbuf) == 2)
- strcat(cwdbuf, "\\");
-
- return(cwdbuf);
- }
-
- /* Z X C M D -- Run a system command so its output can be read like a file */
-
- int
- zxcmd(filnum,comand) int filnum; char *comand; {
- char *name;
- char *cmdbuf;
- extern char *tempnam();
-
- if (! pipename[0]) /* If no pipe has been used yet */
- strcpy(pipename, tempnam(NULL, "ck")); /* Get a name for the pipe */
-
- cmdbuf = malloc(strlen(comand) + 2 + strlen(pipename) + 1);
- strcpy(cmdbuf, comand);
- strcat(cmdbuf, " >");
- strcat(cmdbuf, pipename);
- tossystem(cmdbuf);
- free(cmdbuf);
-
- fp[ZIFILE] = fopen(pipename,"r"); /* open a stream for it */
- fp[ZSYSFN] = fp[ZIFILE]; /* Remember. */
- debug(F101,"zxcmd fp","", fp[ZSYSFN]);
- return(1);
- }
-
- /* Z C L O S F - wait for the child fork to terminate and close the pipe. */
-
- int
- zclosf(filnum) int filnum; {
- debug(F101,"zclosf filnum","",filnum);
- debug(F101,"zclosf fp[filnum]","",(int) fp[filnum]);
- debug(F101,"zclosf fp[ZSYSFN]","",(int) fp[ZSYSFN]);
-
- fclose(fp[filnum]);
- zdelet(pipename);
- fp[filnum] = fp[ZSYSFN] = NULL;
- return(1);
- }
-
- /* Z X P A N D -- Expand a wildcard string into an array of strings */
- /*
- Returns the number of files that match fn1, with data structures set up
- so that first file (if any) will be returned by the next znext() call.
- Depends on external variable wildxpand: 0 means we expand wildcards
- internally, nonzero means we call the shell to do it.
- */
-
- int
- zxpand(fn) char *fn; {
- char *p;
-
- #ifdef DTILDE /* Built with tilde-expansion? */
- char *tnam;
- #endif /* DTILDE */
- debug(F111,"zxpand entry",fn,wildxpand);
- #ifdef DTILDE /* Built with tilde-expansion? */
- if (*fn == '~') { /* Starts with tilde? */
- tnam = tilde_expand(fn); /* Try to expand it. */
- if (tnam) fn = tnam;
- }
- debug(F110,"zxpand after tilde_x",fn,0);
- #endif /* DTILDE */
- if (wildxpand) /* Who is expanding wildcards? */
- fcount = shxpand(fn,mtchs,MAXWLD); /* Shell */
- else
- fcount = fgen(fn,mtchs,MAXWLD); /* Kermit */
- if (fcount > 0) {
- mtchptr = mtchs; /* Save pointer for next. */
- }
- if (fcount > 0) {
- debug(F111,"zxpand ok",mtchs[0],fcount);
- return(fcount);
- }
- debug(F111,"zxpand fgen1",fn,fcount); /* Didn't get one, or got too many */
- p = malloc(strlen(fn) + 10); /* Make space */
- if (!p) return(0);
- zrtol(fn,p); /* Try again, maybe lowercase */
- if (wildxpand)
- fcount = shxpand(p,mtchs,MAXWLD); /* Shell */
- else
- fcount = fgen(p,mtchs,MAXWLD); /* Kermit */
- if (fcount > 0) { /* Got one? */
- mtchptr = mtchs; /* Save pointer for next. */
- debug(F111,"zxpand fgen2 ok",mtchs[0],fcount);
- } else debug(F111,"zxpand 2 not ok",p,fcount);
- free(p);
- return(fcount);
- }
-
-
- /* Z N E X T -- Get name of next file from list created by zxpand(). */
- /*
- Returns >0 if there's another file, with its name copied into the arg string,
- or 0 if no more files in list.
- */
- int
- znext(fn) char *fn; {
- if (fcount-- > 0) {
- strcpy(fn,*mtchptr);
- free(*mtchptr++);
- }
- else *fn = '\0';
- debug(F111,"znext",fn,fcount+1);
- return(fcount+1);
- }
-
-
- /* Z C H K S P A -- Check if there is enough space to store the file */
-
- /*
- Call with file specification f, size n in bytes.
- Returns -1 on error, 0 if not enough space, 1 if enough space.
- */
- struct disk_info {
- unsigned long di_free; /* Free allocation units */
- unsigned long di_many; /* Allocation units per disk */
- unsigned long di_ssize; /* Sector size (in bytes) */
- unsigned long di_spau; /* Sectors per allocation unit */
- };
-
- int
- zchkspa(f,n) char *f; long n; {
- int drive;
- struct disk_info disk;
- long bytesleft;
-
- drive = Dgetdrv();
- Dfree(&disk, 0); /* Check current drive */
- bytesleft = disk.di_free * disk.di_spau * disk.di_ssize;
- if (n > bytesleft)
- return(0);
-
- return(1); /* Always say OK. */
- }
-
-
- /* Z N E W N -- Make a new name for the given file */
-
- /*
- Given the name, fn, of a file that already exists, this function builds a
- new name of the form "<oldname><n>" where <oldname> is the (possibly
- truncated) argument name (fn) and <n> is a version number, one higher
- than any existing version number for that file, up to 99. If the
- constructed name is too long for the system's maximum, enough characters
- are truncated from the end of <fn> to allow the version number to fit.
- If no free version numbers exist between 0 and 99, a version number of
- "xx" is used. Returns a pointer to the new name in argument s.
- */
-
- VOID
- znewn(fn,s) char *fn, **s; {
- #define ZNEWNBL 13 /* Name buffer length */
- #define ZNEWNMD 2 /* Max digits for version number */
- #define ZNEWEXT 3 /* Max chars in extension */
- #define ZNEWPRE 8 /* Max chars in prefix */
- #define ZNEWTRC (ZNEWPRE-ZNEWNMD) /* Max chars in truncated prefix */
- static char buf[ZNEWNBL+1];
- char prefix[ZNEWPRE+1];
- char extension[ZNEWEXT+1];
- char *bp, *xp;
- int len, n, t, d;
-
- bp = strchr(fn, '.'); /* First save the extension */
- if (bp) {
- strncpy(extension, bp+1, ZNEWEXT);
- extension[ZNEWEXT] = '\0';
- } else
- extension[0] = '\0';
-
- strncpy(prefix, fn, ZNEWPRE); /* Now save the prefix */
- prefix[ZNEWPRE] = '\0';
- bp = strchr(prefix, '.'); /* Seems wasteful to do this again */
- if (bp)
- *bp = '\0'; /* Get rid of period and extension */
-
- len = strlen(prefix); /* Pad to six bytes with zeroes */
- for (; len < ZNEWTRC; len++)
- prefix[len] = '0';
- prefix[ZNEWTRC] = '\0';
-
- strcpy(buf, prefix); /* Create wildcard string */
- strcat(buf, "*.");
- strcat(buf, extension);
- n = zxpand(buf); /* Expand the resulting wild name */
-
- d = -1; /* Initialize lowest unused */
- while (n-- > 0) { /* Find any existing name<n> files */
- xp = *mtchptr++; /* Point at matching name */
- if ( (strchr(xp, '.') - xp) > ZNEWTRC &&
- isdigit(xp[ZNEWTRC]) ) { /* Look for <n> prefix end */
- t = atoi(&xp[ZNEWTRC]); /* Get it */
- if (t > d) d = t; /* Save d = highest version number */
- }
- }
- d++; /* Lowest unused version number */
-
- strcpy(buf, prefix); /* First copy truncated prefix */
- for (len = ZNEWPRE-1; len >= ZNEWTRC; len--) {
- buf[len] = '0' + d % 10;
- d /= 10;
- }
- if (d) { /* If it didn't fit use 'X' */
- for (len = ZNEWPRE-1; len >= ZNEWTRC; len--)
- buf[len] = 'X';
- }
- buf[ZNEWPRE] = '.'; /* Don't forget the period */
- buf[ZNEWPRE+1] = '\0';
- strcat(buf, extension); /* Tack on extension */
- *s = buf; /* Tell caller buffer location */
- return;
- }
-
- /* Z R E N A M E -- Rename a file */
-
- /* Note, link() and unlink() are used because rename() is not available */
- /* in some versions of UNIX. */
- /* Call with old and new names */
- /* Returns 0 on success, -1 on failure. */
-
- int
- zrename(old,new) char *old, *new; {
- return(Frename(0, old, new) != 0 ? -1 : 0);
- }
-
- /* Z S A T T R */
- /*
- Fills in a Kermit file attribute structure for the file which is to be sent.
- Returns 0 on success with the structure filled in, or -1 on failure.
- If any string member is null, then it should be ignored.
- If any numeric member is -1, then it should be ignored.
- */
- int
- zsattr(xx) struct zattr *xx; {
- long k;
- char *zfcdat();
-
- k = iflen % 1024L; /* File length in K */
- if (k != 0L) k = 1L;
- xx->lengthk = (iflen / 1024L) + k;
- xx->type.len = 0; /* File type can't be filled in here */
- xx->type.val = "";
- if (*nambuf) {
- xx->date.val = zfcdat(nambuf); /* File creation date */
- xx->date.len = strlen(xx->date.val);
- } else {
- xx->date.len = 0;
- xx->date.val = "";
- }
- xx->creator.len = 0; /* File creator */
- xx->creator.val = "";
- xx->account.len = 0; /* File account */
- xx->account.val = "";
- xx->area.len = 0; /* File area */
- xx->area.val = "";
- xx->passwd.len = 0; /* Area password */
- xx->passwd.val = "";
- xx->blksize = -1L; /* File blocksize */
- xx->access.len = 0; /* File access */
- xx->access.val = "";
- xx->encoding.len = 0; /* Transfer syntax */
- xx->encoding.val = 0;
- xx->disp.len = 0; /* Disposition upon arrival */
- xx->disp.val = "";
- xx->lprotect.len = 0; /* Local protection */
- xx->lprotect.val = "";
- xx->gprotect.len = 0; /* Generic protection */
- xx->gprotect.val = "";
- xx->systemid.len = 2; /* System ID */
- xx->systemid.val = "U1";
- xx->recfm.len = 0; /* Record format */
- xx->recfm.val = "";
- xx->sysparam.len = 0; /* System-dependent parameters */
- xx->sysparam.val = "";
- xx->length = iflen; /* Length */
- return(0);
- }
-
- /* Z F C D A T -- Get file creation date */
- /*
- Call with pointer to filename.
- On success, returns pointer to creation date in yyyymmdd hh:mm:ss format.
- On failure, returns pointer to null string.
- */
- static char datbuf[40];
-
- char *
- zfcdat(name) char *name; {
-
- #ifdef TIMESTAMP
- struct stat buffer;
- struct tm *time_stamp, *localtime();
- int yy, ss;
-
- datbuf[0] = '\0';
- if(stat(name,&buffer) != 0) {
- debug(F110,"zfcdat stat failed",name,0);
- return("");
- }
- time_stamp = localtime(&(buffer.st_mtime));
- yy = time_stamp->tm_year;
- if (yy < 100) /* In case it returns 2-digit year? */
- yy += 1900;
- if (yy < 0 || yy > 9999) { /* Make sure year is ok */
- debug(F110,"zfcdat date failed",name,0);
- return("");
- }
- if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11)
- return("");
- if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31)
- return("");
- if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23)
- return("");
- if (time_stamp->tm_min < 0 || time_stamp->tm_min > 59)
- return("");
- ss = time_stamp->tm_sec; /* Seconds */
- if (ss < 0 || ss > 59) /* Some systems give a BIG number */
- ss = 0;
- sprintf(datbuf,
- "%04d%02d%02d %02d:%02d:%02d",
- yy,
- time_stamp->tm_mon + 1,
- time_stamp->tm_mday,
- time_stamp->tm_hour,
- time_stamp->tm_min
- , ss
- );
- yy = strlen(datbuf);
- debug(F111,"zfcdat",datbuf,yy);
- if (yy > 17) datbuf[17] = '\0';
- return(datbuf);
- #else
- return("");
- #endif /* TIMESTAMP */
- }
-
- /* Z S T I M E -- Set creation date for incoming file */
- /*
- Call with:
- f = pointer to name of existing file.
- yy = pointer to a Kermit file attribute structure in which yy->date.val
- is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
- x = is a function code: 0 means to set the file's creation date as given.
- 1 means compare the given date with the file creation date.
- Returns:
- -1 on any kind of error.
- 0 if x is 0 and the file date was set successfully.
- 0 if x is 1 and date from attribute structure <= file creation date.
- 1 if x is 1 and date from attribute structure > file creation date.
- */
- int
- zstime(f,yy,x) char *f; struct zattr *yy; int x; {
- int r = -1; /* return code */
- /*
- It is ifdef'd TIMESTAMP because it may not work on V7. bk@kullmar.se.
- */
- #ifdef TIMESTAMP
- /*
- To do: adapt code from OS-9 Kermit's ck9fio.c zstime function, which
- is more flexible, allowing [yy]yymmdd[ hh:mm[:ss]].
- */
- extern int ftime();
- long tm, days;
- int i, n, isleapyear, stat(), utime();
- /* J F M A M J J A S O N D */
- /* 31 28 31 30 31 30 31 31 30 31 30 31 */
- static
- int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 };
- char s[5], *getenv();
- extern struct tm *localtime();
- struct stat sb;
- struct utimbuf {
- time_t atime; /* New access time */
- time_t mtime; /* New modification time */
- } tp;
-
- debug(F110,"zstime",f,0);
-
- if ((yy->date.len == 0)
- || (yy->date.len != 17)
- || (yy->date.val[8] != ' ')
- || (yy->date.val[11] != ':')
- || (yy->date.val[14] != ':') ) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- debug(F111,"zstime date check 1",yy->date.val,yy->date.len);
- for(i = 0; i < 8; i++) {
- if (!isdigit(yy->date.val[i])) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- }
- debug(F111,"zstime date check 2",yy->date.val,yy->date.len);
- i++;
-
- for (; i < 16; i += 3) {
- if ((!isdigit(yy->date.val[i])) || (!isdigit(yy->date.val[i + 1]))) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- }
- debug(F111,"zstime date check 3",yy->date.val,yy->date.len);
-
- s[4] = '\0';
- for (i = 0; i < 4; i++) /* Fix the year */
- s[i] = yy->date.val[i];
-
- debug(F110,"zstime year",s,0);
-
- n = atoi(s);
-
- debug(F111,"zstime year",s,n);
-
- /* Previous year's leap days. This won't work after year 2100, */
- /* I don't care about that! */
- isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
- days = (long) (n - 1970) * 365;
- days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
-
- s[2] = '\0';
-
- for (i = 4 ; i < 16; i += 2) {
- s[0] = yy->date.val[i];
- s[1] = yy->date.val[i + 1];
- n = atoi(s);
- debug(F110,"zstime entering switch",s,0);
- switch (i) {
- case 4: /* MM: month */
- if ((n < 1 ) || ( n > 12)) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- days += monthdays [n];
- if (isleapyear && n > 2)
- ++days;
- continue;
-
- case 6: /* DD: day */
- if ((n < 1 ) || ( n > 31)) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- tm = (days + n - 1) * 24L * 60L * 60L;
- i++; /* Skip the space */
- continue;
-
- case 9: /* hh: hour */
- if ((n < 0 ) || ( n > 23)) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- tm += n * 60L * 60L;
- i++; /* Skip the colon */
- continue;
-
- case 12: /* mm: minute */
- if ((n < 0 ) || ( n > 59)) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- tm += timezone - dstadjust; /* Correct for time zone */
-
- tm += n * 60L;
- i++; /* Skip the colon */
- continue;
-
- case 15: /* ss: second */
- if ((n < 0 ) || ( n > 59)) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- tm += n;
- }
- }
-
- debug(F111,"Attribute creation date ok ",yy->date.val,yy->date.len);
-
- if (stat(f,&sb)) { /* Get the time for the file */
- debug(F110,"Can't stat file:",f,0);
- return(-1);
- }
- tp.mtime = tm; /* Set modif. time to creation date */
- tp.atime = sb.st_atime; /* Don't change the access time */
-
- switch (x) { /* Execute desired function */
- case 0: /* Set the creation date of the file */
- if (utime(f,&tp)) { /* Fix modification time */
- debug(F110,"Can't set modification time for file: ",f,0);
- r = -1;
- } else {
- debug(F110,"Modification time is set for file: ",f,0);
- r = 0;
- }
- break;
- case 1: /* Compare the dates */
- debug(F111,"zstime compare",f,sb.st_atime);
- debug(F111,"zstime compare","packet",tm);
- if (sb.st_atime < tm) r = 0; else r = 1;
- break;
- default: /* Error */
- r = -1;
- }
- #endif /* TIMESTAMP */
- return(r);
- }
-
- /* Find initialization file. */
-
- int
- zkermini(line, flag, def) char *line; int flag; char *def; {
- #ifdef NOICP
- return(0);
- #else
- extern char *homdir, *lp;
-
- homdir = zhome();
- lp = line;
- strcpy(lp, def);
-
- if (flag) /* If init file name from cmd line */
- ; /* use it */
- else if (zchki(lp) >= 0) /* Then try current directory */
- ; /* If it exists, use it */
- else if (homdir) { /* Then try home directory (if any) */
- strcpy(lp, homdir);
- strcat(lp, "\\");
- strcat(lp, def);
- if (zchki(lp) >= 0) /* If it exists, use it */
- return(0);
- } else { /* Then try root directory */
- strcpy(lp, "\\");
- strcat(lp, def);
- }
- return(0);
- #endif /* NOICP */
- }
-
- #ifndef NOFRILLS
- int
- zmail(p,f) char *p; char *f; { /* Send file f as mail to address p */
- return(0);
- }
- #endif /* NOFRILLS */
-
- #ifndef NOFRILLS
- int
- zprint(p,f) char *p; char *f; { /* Print file f with options p */
- sprintf(zmbuf,"pr %s >prn:", f); /* Construct print command */
- zsyscmd(zmbuf);
- return(0);
- }
- #endif /* NOFRILLS */
-
- /*
- Wildcard expansion functions. C-Kermit used to do this itself (see #else
- part...). New code (version 5A, 1990-91) just asks UNIX to do it.
- This lets users use the wildcard expansion features of their favorite shell.
- Operation is slower because of the forking & piping, but flexibility is
- greater and program is smaller.
- */
-
- static char scratch[MAXPATH+4]; /* Used by both methods */
-
- static int oldmtchs = 0; /* Let shell (ls) expand them. */
- #ifdef COMMENT
- static char *lscmd = "/bin/ls -d"; /* Command to use. */
- #else
- static char *lscmd = "echo"; /* Command to use. */
- #endif /* COMMENT */
-
- int
- shxpand(pat,namlst,len) char *pat, *namlst[]; int len; {
- char *fgbuf = NULL; /* Buffer for forming ls command */
- char *p, *q; /* Workers */
- int i, x, retcode; char c; /* ... */
-
- x = strlen(pat) + strlen(lscmd) + 3; /* Length of ls command */
- for (i = 0; i < oldmtchs; i++) /* Free previous file list */
- free(namlst[i]);
- fgbuf = malloc(x); /* Get buffer for command */
- if (!fgbuf) return(-1); /* Fail if cannot */
- sprintf(fgbuf,"%s %s",lscmd,pat); /* Form the command */
- zxcmd(ZIFILE,fgbuf); /* Start the command */
- i = 0; /* File counter */
- p = scratch; /* Point to scratch area */
- retcode = -1; /* Assume failure */
- while ((c = zminchar()) != -1) { /* Read characters from command */
- if (c == ' ' || c == '\n') { /* Got newline or space? */
- *p = '\0'; /* Yes, terminate string */
- p = scratch; /* Point back to beginning */
- if (zchki(p) == -1) /* Does file exist? */
- continue; /* No, continue */
- x = strlen(p); /* Yes, get length of name */
- q = malloc(x+1); /* Allocate space for it */
- if (!q) goto shxfin; /* Fail if space can't be obtained */
- strcpy(q,scratch); /* Copy name to space */
- namlst[i++] = q; /* Copy pointer to name into array */
- if (i > len) goto shxfin; /* Fail if too many */
- } else { /* Regular character */
- *p++ = c; /* Copy it into scratch area */
- }
- }
- retcode = i; /* Return number of matching files */
- shxfin: /* Common exit point */
- free(fgbuf); /* Free command buffer */
- zclosf(ZIFILE); /* Delete the command fork. */
- oldmtchs = i; /* Remember how many files */
- return(retcode);
- }
-
- /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
-
- /* Define the size of the string space for filename expansion. */
-
- #ifndef DYNAMIC
- #ifdef PROVX1
- #define SSPACE 500
- #else
- #ifdef BSD29
- #define SSPACE 500
- #else
- #ifdef pdp11
- #define SSPACE 500
- #else
- #ifdef aegis
- #define SSPACE 10000 /* size of string-generating buffer */
- static char bslash; /* backslash character if active */
- #else /* Default static buffer size */
- #define SSPACE 2000 /* size of string-generating buffer */
- #endif /* aegis */
- #endif /* pdp11 */
- #endif /* BSD29 */
- #endif /* PROVX1 */
- static char sspace[SSPACE]; /* buffer for generating filenames */
- #else /* DYNAMIC */
- #define SSPACE 10000
- static char *sspace = (char *)0;
- #endif /* DYNAMIC */
- static int ssplen = SSPACE; /* length of string space buffer */
-
- static char *freeptr,**resptr; /* copies of caller's arguments */
- static int remlen; /* remaining length in caller's array*/
- static int numfnd; /* number of matches found */
-
- /*
- * splitpath:
- * takes a string and splits the slash-separated portions into
- * a list of path structures. Returns the head of the list. The
- * structures are allocated by malloc, so they must be freed.
- * Splitpath is used internally by the filename generator.
- *
- * Input: A string.
- * Returns: A linked list of the slash-separated segments of the input.
- */
-
- struct path *
- splitpath(p) char *p; {
- struct path *head,*cur,*prv;
- int i;
-
- debug(F110,"splitpath",p,0);
-
- head = prv = NULL;
- if (*p == '\\') p++; /* skip leading slash */
- while (*p != '\0') {
- cur = (struct path *) malloc(sizeof (struct path));
- debug(F101,"splitpath malloc","",cur);
- if (cur == NULL)
- fatal("malloc fails in splitpath()");
- cur -> fwd = NULL;
- if (head == NULL)
- head = cur;
- else
- prv -> fwd = cur; /* link into chain */
- prv = cur;
-
- for (i=0;
- i < MAXNAMLEN && *p != '\\' && *p != ':' && *p != '\0';
- i++)
- cur -> npart[i] = *p++;
- if ( *p == ':' ) {
- cur -> npart[i++] = *p++;
- if ( *p != '\\' )
- cur -> npart[i++] = '.';
- }
- cur -> npart[i] = '\0'; /* end this segment */
- if (i >= MAXNAMLEN)
- while (*p != '\\' && *p != '\0') p++;
- if (*p == '\\')
- p++;
- }
- return(head);
- }
-
- /* Directory Functions for GEMDOS, hacked up by Bruce Moore, 1991 */
-
- /*
- * fgen:
- * This is the actual name generator. It is passed a string,
- * possibly containing wildcards, and an array of character pointers.
- * It finds all the matching filenames and stores them into the array.
- * The returned strings are allocated from a static buffer local to
- * this module (so the caller doesn't have to worry about deallocating
- * them); this means that successive calls to fgen will wipe out
- * the results of previous calls. This isn't a problem here
- * because we process one wildcard string at a time.
- *
- * Input: a wildcard string, an array to write names to, the
- * length of the array.
- * Returns: the number of matches. The array is filled with filenames
- * that matched the pattern. If there wasn't enough room in the
- * array, -1 is returned.
- * By: Jeff Damens, CUCCA, 1984.
- */
- static int
- fgen(pat,resarry,len) char *pat,*resarry[]; int len; {
- int numfnd;
-
- numfnd = traverse(pat,resarry,len); /* go walk the directory tree */
- if (numfnd >= len)
- return(-1);
- return(numfnd); /* and return the number of matches */
- }
-
- /* traverse:
- * Walks the directory tree looking for matches to its arguments.
- * The algorithm is, briefly:
- * If the current pattern segment contains no wildcards, that
- * segment is added to what we already have. If the name so far
- * exists, we call ourselves recursively with the next segment
- * in the pattern string; otherwise, we just return.
- *
- * If the current pattern segment contains wildcards, we open the name
- * we've accumulated so far (assuming it is really a directory), then read
- * each filename in it, and, if it matches the wildcard pattern segment, add
- * that filename to what we have so far and call ourselves recursively on the
- * next segment.
- *
- * Finally, when no more pattern segments remain, we add what's accumulated
- * so far to the result array and increment the number of matches.
- *
- * Input: a pattern path list (as generated by splitpath), a string
- * pointer that points to what we've traversed so far (this
- * can be initialized to "/" to start the search at the root
- * directory, or to "./" to start the search at the current
- * directory), and a string pointer to the end of the string
- * in the previous argument.
- * Returns: nothing.
- */
- static VOID
- traverse(name, wildnames, maxwild)
- char *name;
- char *wildnames[];
- int maxwild;
- {
- DMABUFFER dma;
- DMABUFFER *saved;
- char *p;
- int found;
-
- found = 0;
- saved = (DMABUFFER *) Fgetdta();
- Fsetdta(&dma);
-
- if (Fsfirst(name, S_IJRON) == 0) { /* Found one */
- do {
- strcpy(scratch, name);
- if (p = strrchr(scratch, '\\'))
- p++;
- else
- p = scratch;
- *p = '\0';
- strcat(scratch, dma.d_fname);
- wildnames[found] = malloc(strlen(scratch) + 1);
- strcpy(wildnames[found++], scratch);
- if (found >= maxwild)
- break;
- } while (Fsnext() == 0);
- }
- Fsetdta(saved);
- return(found);
- }
-
- /* The following function is for expanding tilde in filenames
- * Contributed by Howie Kaye, CUCCA, developed for CCMD package.
- */
-
- /* T I L D E _ E X P A N D -- expand ~user to the user's home directory. */
-
- #define DIRSEP '\\'
-
- char *
- tilde_expand(dirname) char *dirname; {
- #define BUFLEN 256
- #ifdef DTILDE
- static char olddir[BUFLEN];
- static char oldrealdir[BUFLEN];
- static char temp[BUFLEN];
- int i, j;
- char *user;
-
- debug(F111,"tilde_expand",dirname,dirname[0]);
-
- if (dirname[0] != '~') /* Not a tilde...return param */
- return(dirname);
- if (!strcmp(olddir,dirname)) { /* Same as last time */
- return(oldrealdir); /* so return old answer. */
- } else {
- j = strlen(dirname);
- for (i = 0; i < j; i++) /* find username part of string */
- if (dirname[i] != DIRSEP)
- temp[i] = dirname[i];
- else break;
- temp[i] = '\0'; /* tie off with a NULL */
- if (i == 1) { /* if just a "~" */
- user = "?"; /* No info, we're single user */
- } else {
- user = NULL; /* otherwise on the specified user */
- }
- }
- if (user != NULL) { /* valid user? */
- strcpy(olddir, dirname); /* remember the directory */
- strcpy(oldrealdir, zhome()); /* and their home directory */
- strcat(oldrealdir,&dirname[i]);
- return(oldrealdir);
- } else { /* invalid? */
- strcpy(olddir, dirname); /* remember for next time */
- strcpy(oldrealdir, dirname);
- return(oldrealdir);
- }
- #else
- return(NULL);
- #endif /* dtilde */
- }
-
- /*
- Functions for executing system commands.
- zsyscmd() executes the system command in the normal, default way for
- the system. In UNIX, it does what system() does. Thus, its results
- are always predictable.
- zshcmd() executes the command using the user's preferred shell.
- */
- int
- zsyscmd(s) char *s; {
- return(tossystem(s));
- }
-
- /*
- UNIX code by H. Fischer; copyright rights assigned to Columbia Univ.
- Adapted to use getpwuid to find login shell because many systems do not
- have SHELL in environment, and to use direct calling of shell rather
- than intermediate system() call. -- H. Fischer
- Call with s pointing to command to execute.
- */
-
- int
- zshcmd(s) char *s; {
- tossystem(s);
- return(1);
- }
-
- /* I S W I L D -- Check if filespec is "wild" */
-
- /*
- Returns 0 if it is a single file, 1 if it contains wildcard characters.
- Note: must match the algorithm used by match(), hence no [a-z], etc.
- */
- int
- iswild(filespec) char *filespec; {
- char c; int x; char *p;
- if (wildxpand) {
- if ((x = zxpand(filespec)) > 1) return(1);
- p = malloc(MAXNAMLEN + 20);
- znext(p);
- x = (strcmp(filespec,p) != 0);
- free(p);
- return(x);
- } else {
- while ((c = *filespec++) != '\0')
- if (c == '*' || c == '?') return(1);
- return(0);
- }
- }
-
- /* T O S S Y S T E M -- Execute a system command */
- /*
- Use gulam if present, otherwise hope for MSH, the shell supplied
- with the Mark Williams C package.
- */
- #define SHELLP ((char **) 0x04f6L)
- #define G_MAGIC 0x0135
-
- tossystem(cmd)
- char *cmd;
- {
- long save_ssp;
- short sh_magic;
- char *tgptr; /* storage for togu_ */
- int (* cgp)(); /* pointer to callgulam() */
-
- save_ssp = Super(0L); /* Get gulam stuff in Supervisor mode */
- if ((tgptr = *SHELLP)) { /* NULL need not apply */
- sh_magic = *((short *)(tgptr - 8));
- cgp = *((int (*)()) tgptr);
- } else
- sh_magic = 0;
- Super(save_ssp);
-
- if (sh_magic == G_MAGIC) /* Gulam??? */
- (* cgp) (cmd);
- else /* No, hope for MSH */
- system(cmd);
- }
-